/*
  File: RedisDBHelper.cs
  Author: rcrxy
  CreateTime: 2025/07/01 10:22

  Description:
*/

using Microsoft.EntityFrameworkCore;
using StackExchange.Redis;

namespace StudentVideo.Helper;

public class RedisDbHelper(IDatabase database, ILogger<RedisDbHelper> logger) {
   private readonly ILogger<RedisDbHelper> _logger = logger;

   public readonly IDatabase Db = database;

   public class SyncToRedisFunc<T> {

      /// <summary>
      /// 创建
      /// </summary>
      public Func<T, Task>? Create;

      /// <summary>
      /// 修改
      /// </summary>
      public Func<T, Task>? Update;

      /// <summary>
      /// 删除
      /// </summary>
      public Func<T, Task>? Delete;
   }

   public async Task SyncToRedis<TEntity>(DbContext? context, SyncToRedisFunc<TEntity> operate) {
      if (context == null)
         return;

      var entries = context.ChangeTracker
         .Entries()
         .Where(e => typeof(TEntity).IsAssignableFrom(e.Metadata.ClrType))
         .ToList();

      if (entries.Count == 0) return;

      // 按状态分组处理
      var added = entries.Where(e => e.State == EntityState.Added);
      var modified = entries.Where(e => e.State == EntityState.Modified);
      var deleted = entries.Where(e => e.State == EntityState.Deleted);

      try {
         foreach (var entity in added) {
            if (operate.Create != null)
               await operate.Create((TEntity)entity.Entity);
         }
         foreach (var entity in modified) {
            if (operate.Update != null)
               await operate.Update((TEntity)entity.Entity);
         }
         foreach (var entity in deleted) {
            if (operate.Delete != null)
               await operate.Delete((TEntity)entity.Entity);
         }
      } catch (Exception ex) {
         _logger.LogError(ex, "[SyncToRedis Error] Entity: {type}", typeof(TEntity));
      }
      return;
   }

}

public static class RedisDBHelperExtension {

   /// <summary>
   /// RedisValue 转换为指定集合
   /// </summary>
   /// <typeparam name="TResult"></typeparam>
   /// <typeparam name="TItem"></typeparam>
   /// <param name="redisDb"></param>
   /// <param name="value"></param>
   /// <param name="converter"></param>
   /// <returns></returns>
   public static TResult RedisValueToCollection<TResult, TItem>(
      this RedisDbHelper redisDb,
      RedisValue value,
      Func<string, TItem> converter
   ) where TResult : ICollection<TItem>, new() {
      var result = new TResult();

      if (!value.IsNullOrEmpty) {
         var items = value.ToString()
             .Split(',', StringSplitOptions.RemoveEmptyEntries)
             .Select(converter);

         foreach (var item in items) {
            result.Add(item);
         }
      }

      return result;
   }
}
